<?php
// $Id: Log.php 27 2010-11-16 12:49:54Z mjohnson60@gmail.com $

// System is unusable
define('LOG_EMERGENCY', 0);

// Immediate action required
define('LOG_ALERT', 1);

// Critical conditions
define('LOG_CRITICAL', 2);

// Error conditions
define('LOG_ERROR', 3);

// Warning conditions
define('LOG_WARNING', 4);

// Normal but significant
define('LOG_NOTICE', 5);

// Informational
define('LOG_INFO', 6);

// Debug-level messages
define('LOG_DEBUG', 7);

/**
 * Enter description here ...
 * 
 * @author Mark Phillip Johnson
 * @version 1.0
 * @copyright Copyright (c) 2010, markjohnson
 * @license http://www.gnu.org/licenses/gpl.html The GNU General Public License v3.0
 *
 */
class Log
{
	private static $instance = NULL;
	
	var $options = array();
	var $level = self::INFO;
	
	var $logs = array();

	/**
	 * Class constructor.
	 *
	 * @see initialize()
	 */
	public function __construct($options = array())
	{
		self::$instance = & $this;
		
		$this->initialize($options);
		
		if (!isset($options['auto_shutdown']) || $options['auto_shutdown'])
		{
			register_shutdown_function(array(
				$this, 
				'shutdown'
			));
		}
	}

	/**
	 * Enter description here ...
	 * @return NULL
	 */
	public static function &getInstance()
	{
		if (!isset(self::$instance))
		{
			new Log();
		}
		
		return self::$instance;
	}

	/**
	 * Initializes this sfLogger instance.
	 *
	 * Available options:
	 *
	 * - level: The log level.
	 *
	 * @param  sfEventDispatcher $dispatcher  A sfEventDispatcher instance
	 * @param  array             $options     An array of options.
	 *
	 * @return Boolean      true, if initialization completes successfully, otherwise false.
	 *
	 * @throws <b>sfInitializationException</b> If an error occurs while initializing this sfLogger.
	 */
	public function initialize($options = array())
	{
		$this->options = $options;
		
		if (isset($this->options['level']))
		{
			$this->setLogLevel($this->options['level']);
		}
	}

	public static function getLogs()
	{
		$_this = & Log::getInstance();
		return $_this->logs;
	}

	/**
	 * Returns the options for the logger instance.
	 */
	public static function getOptions()
	{
		$_this = & Log::getInstance();
		return $_this->options;
	}

	/**
	 * Returns the options for the logger instance.
	 */
	public static function setOption($name, $value)
	{
		$_this = & Log::getInstance();
		$_this->options[$name] = $value;
	}

	/**
	 * Retrieves the log level for the current logger instance.
	 *
	 * @return string Log level
	 */
	public static function getLogLevel()
	{
		$_this = & Log::getInstance();
		return $_this->level;
	}

	/**
	 * Sets a log level for the current logger instance.
	 *
	 * @param string $level Log level
	 */
	public static function setLogLevel($level)
	{
		$_this = & Log::getInstance();
		if (!is_int($level))
		{
			$level = constant('sfLogger::' . strtoupper($level));
		}
		
		$_this->level = $level;
	}

	/**
	 * Logs a message.
	 *
	 * @param string $message   Message
	 * @param string $priority  Message priority
	 */
	public static function log($message, $variables = array(), $priority = LOG_INFO, $link = '')
	{
		if (Log::getLogLevel() < $priority)
		{
			return false;
		}
		
		return Log::doLog($message, $variables, $priority, $link);
	}

	/**
	 * Logs a message.
	 *
	 * @param string $message   Message
	 * @param string $priority  Message priority
	 */
	protected static function doLog($message, $variables, $priority, $link)
	{
		$_this = & Log::getInstance();
		$_this->logs[] = array(
			'priority' => $priority, 
			'priority_name' => $this->getPriorityName($priority), 
			'timestamp' => time(), 
			'message' => $message, 
			'variables' => serialize($variables), 
			'link' => $link
		);
	}

	/**
	 * Logs an emerg message.
	 *
	 * @param string $message Message
	 */
	public static function emerg($message)
	{
		Log::log($message, LOG_EMERGENCY);
	}

	/**
	 * Logs an alert message.
	 *
	 * @param string $message Message
	 */
	public static function alert($message)
	{
		Log::log($message, LOG_ALERT);
	}

	/**
	 * Logs a critical message.
	 *
	 * @param string $message Message
	 */
	public static function crit($message)
	{
		Log::log($message, LOG_CRITICAL);
	}

	/**
	 * Logs an error message.
	 *
	 * @param string $message Message
	 */
	public static function err($message)
	{
		Log::log($message, LOG_ERROR);
	}

	/**
	 * Logs a warning message.
	 *
	 * @param string $message Message
	 */
	public static function warning($message)
	{
		Log::log($message, LOG_WARNING);
	}

	/**
	 * Logs a notice message.
	 *
	 * @param string $message Message
	 */
	public static function notice($message)
	{
		Log::log($message, LOG_NOTICE);
	}

	/**
	 * Logs an info message.
	 *
	 * @param string $message Message
	 */
	public static function info($message)
	{
		Log::log($message, LOG_INFO);
	}

	/**
	 * Logs a debug message.
	 *
	 * @param string $message Message
	 */
	public static function debug($message)
	{
		Log::log($message, LOG_DEBUG);
	}

	/**
	 * Executes the shutdown procedure.
	 *
	 * Cleans up the current logger instance.
	 */
	public function shutdown()
	{
		$referer = referer_uri();
		$location = Config::baseUrl() . request_uri();
		$hostname = Config::baseUrl();
		
		foreach ($this->logs as $log)
		{
			Db::query("INSERT INTO log (priority, message, variables, link, location, referer, hostname, timestamp) VALUES (%d, %b, %b, '%s', %b, %b, '%s', %d)", array(
				$log['priority'], 
				$log['message'], 
				$log['variables'], 
				$log['link'], 
				$location, 
				$referer, 
				$hostname, 
				$log['timestamp']
			));
		}
	}

	/**
	 * Returns the priority name given a priority class constant
	 *
	 * @param  integer $priority A priority class constant
	 *
	 * @return string  The priority name
	 *
	 * @throws sfException if the priority level does not exist
	 */
	public static function getPriorityName($priority)
	{
		static $levels = array(
			LOG_EMERGENCY => 'emergency', 
			LOG_ALERT => 'alert', 
			LOG_CRITICAL => 'critical', 
			LOG_ERROR => 'error', 
			LOG_WARNING => 'warning', 
			LOG_NOTICE => 'notice', 
			LOG_INFO => 'info', 
			LOG_DEBUG => 'debug'
		);
		
		if (!isset($levels[$priority]))
		{
			throw new HrException(sprintf('The priority level "%s" does not exist.', $priority));
		}
		
		return $levels[$priority];
	}
}